#include <stdlib.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <file_cache.h>
#include <time.h>
#include <stdio.h>
#include <string.h>
#include <flache_debug.h>
#include <flache_cleaner.h>

static int remove_from_flash( char* path )
{
    char* rm = "rm -f ";
    int length = strlen( rm ) + strlen( path ) + 3;
    char* cmd = (char*)malloc( length );
    sprintf( cmd, "%s\"%s\"", rm, path );
    int result = system( cmd );
    free( cmd );
    return result;
}

int free_flash_space(unsigned long long needed, char *flash_path, struct file_entry_list_t* list)
{
    int i;
    int iter = 0;
    unsigned long long sizeof_oldest = 0;
    struct stat st;
    struct file_entry_t* oldest = NULL;

    if ( DEBUG )
        write_output( "flache_cleaner: clearing space" );

    do
    {        
        oldest = NULL;
        sizeof_oldest = 0;       

        for(i = list->file_count - 1;i >= 0; i--)
        {
            struct file_entry_t* file;
            file = list->entries[i];

            lock_entry( file );
            
            if(stat(file->flash_path,&st) == 0)
            {                
                if( file->handle_count == 0 && (oldest == NULL || file->time_released < oldest->time_released))
                {
                    if(oldest != NULL) unlock_entry( oldest );
                    oldest = file;
                    sizeof_oldest =  (unsigned long long)st.st_blksize * st.st_blocks;                 
                }
                else
                    unlock_entry( file );
            }
            else //remove nonexistant file from list
            {
                remove_file( list, file );
                _free_entry( file ); //removes lock
            }
        }
        
        if( oldest != NULL )
        {    
            if( remove_from_flash( oldest->flash_path ) == 0 )        
            {         
                if ( DEBUG )
                    write_output2( "flache_cleaner: reclaimed ", oldest->path );

                remove_file( list, oldest );
                _free_entry( oldest ); //removes lock

                if ( sizeof_oldest > needed )
                    needed = 0;
                else
                    needed -= sizeof_oldest;
            }
            else
            {
                oldest->time_released = time( NULL);
                iter++;
            }
        }
    }
    while( oldest != NULL && needed > 0 && iter < 16);

    return ( needed <= 0 ) ? 0 : -1;
}

int check_flash_space(size_t size, struct flache_vol_t* volume, struct file_entry_list_t* list)
{
    int result;

 	unsigned long long free = 0;
    unsigned long long total = 0;
    unsigned long long needed = (unsigned long long)size;

  	struct statvfs sfs;
  	if ( statvfs ( volume->flash_path, &sfs ) != -1 )
  	{
  		free = (unsigned long long)sfs.f_bsize * sfs.f_bfree;
        total = (unsigned long long)sfs.f_bsize * sfs.f_blocks;

        needed += ( total * ( PERCENT_BUF/100 ) );

        if(free >= needed)
            result = 0;
        else
        {
            lock_list( list );  
            pthread_mutex_lock( &volume->write_lock );
            result = free_flash_space( needed, volume->flash_path, list );
            pthread_mutex_unlock( &volume->write_lock );
  	        unlock_list( list );
        }    
    }
    else
        result = -1;    

	return result;
}


